package com.sangmo.fts.common.authority.filters;

import com.sangmo.boot.framework.common.utils.UnderlineToCamelUtils;
import com.sangmo.boot.framework.data.filter.Criteria;
import com.sangmo.fts.common.authority.AuthorityFilterChain;
import com.sangmo.fts.common.authority.EntitySearchContext;
import com.sangmo.fts.common.authority.IAuthorityFilter;
import com.sangmo.fts.common.authority.meta.AuthorizeRefAnn;
import com.sangmo.fts.common.authority.sql.NativeSearchContext;
import com.sangmo.fts.common.authority.sql.WhereModifier;
import org.apache.commons.lang3.StringUtils;

import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;

/*
* 解决了权限依赖项目主体对象的问题
* */
public class AuthorizeRefFilter implements IAuthorityFilter<AuthorizeRefAnn> {

    @Override
    public Class<AuthorizeRefAnn> getAnnotation() {
        return AuthorizeRefAnn.class;
    }

    @Override
    public IAuthorityFilter.SearchFilterResult internalSearchFilter(EntitySearchContext context, AuthorizeRefAnn annotation, int expectedRight) {
        CriteriaQuery<?> criteriaQuery = context.getCriteriaBuilder().createQuery();
        Subquery subquery = criteriaQuery.subquery(String.class);
        Root refRoot = subquery.from(annotation.resource());
        subquery.select(refRoot.get("id"));

        Path path = context.getRoot().get(annotation.indicator());
        Predicate p1 = context.getCriteriaBuilder().equal(refRoot.get("id"), path);
        Predicate p2 = AuthorityFilterChain.getInstance().doSearchFilters(new EntitySearchContext(refRoot, context.getCriteriaBuilder()), annotation.refRights());
        Predicate p3 = Criteria.concat(context.getCriteriaBuilder(), p1, p2, false);
        subquery.where(p3);
        Predicate p4 = context.getCriteriaBuilder().exists(subquery);
        return new SearchFilterResult().setPredicate(p4);
    }

    @Override
    public NativeSearchFilterResult internalNativeSearchFilter(NativeSearchContext context, AuthorizeRefAnn annotation, int expectedRight) {

        String refTable = UnderlineToCamelUtils.camelToUnderline(annotation.resource().getSimpleName());
        String refAlias = context.createAlias();

        String subQuery = String.format("SELECT 1 FROM %s AS %s WHERE %s.id = %s.%s",
                refTable, refAlias, refAlias, context.getAlias(), UnderlineToCamelUtils.camelToUnderline(annotation.indicator())
                );

        NativeSearchContext subContext = new NativeSearchContext(refAlias, annotation.resource());
        WhereModifier modifier = AuthorityFilterChain.getInstance().doNativeSearchFilters(subContext, annotation.refRights());

        String andSql = modifier.getSql();
        if (!StringUtils.isEmpty(andSql)) {
            andSql = " AND " + andSql;
        }

        NativeSearchFilterResult nativeSearchFilterResult = new NativeSearchFilterResult();

        nativeSearchFilterResult.setSql(String.format("EXISTS(%s %s)",
                subQuery, andSql
        ));
        nativeSearchFilterResult.getVariables().putAll(modifier.getVariables());
        return nativeSearchFilterResult;
    }
}
